#pragma once
#include <iostream>
#include <variant>
#include <string>
#include <memory>

class FunctionObject;
class NativeFunction;

using FunctionPtr = std::shared_ptr<FunctionObject>;
using NativeFuncPtr = std::shared_ptr<NativeFunction>;

// monostate stands for nil
// ALERT: passing a const char* will convert to bool instead of std::string
// use std::string("123") or "123"s
using Value = std::variant<std::monostate, bool, double, std::string, FunctionPtr, NativeFuncPtr>;

// 对应variant.index()
enum ValueType
{
	NIL = 0,
	BOOL,
	NUMBER,
	STRING,
	FUNCTION,
	NATIVE_FUNCTION
};

std::ostream &operator<<(std::ostream &os, const Value &v);

bool isTrue(const Value &val);

Value operator+(const Value &lhs, const Value &rhs);

Value operator-(const Value &lhs, const Value &rhs);

Value operator*(const Value &lhs, const Value &rhs);

Value operator/(const Value &lhs, const Value &rhs);

bool operator<(const Value &lhs, const Value &rhs);

bool operator>(const Value &lhs, const Value &rhs);

bool operator==(const Value &lhs, const Value &rhs);

bool operator!=(const Value &lhs, const Value &rhs);

bool operator<=(const Value &lhs, const Value &rhs);

bool operator>=(const Value &lhs, const Value &rhs);

bool isCallable(const Value &val);